/*
 * Created on 09-sep-2004
 */
package guru.mercurio.core;

import guru.mercurio.common.AbsoluteApplicationAddress;
import guru.mercurio.common.RelativeApplicationAddress;
import guru.mercurio.data.ChannelDataManager;
import guru.mercurio.data.PassportDataManager;
import guru.merlin.bus.EnvelopeBus;
import guru.merlin.core.Address;
//import guru.merlin.core.CantHandException;
import guru.merlin.core.EPException;
import guru.merlin.core.Envelope;
import guru.merlin.core.EnvelopeEPException;
import guru.merlin.core.InfrastructureEPException;
import guru.merlin.core.Router;
import guru.util.Commander;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;

import org.apache.log4j.Logger;

/**
 * Pasos: 1. Gateway: transformacin del protocolo. 2. Router: direccionamiento a travs del nodo
 * correspondiente.
 *
 * @author cobach
 */

public class MercurioRouter extends Router{
    static Logger logger = Logger.getLogger (MercurioRouter.class);
    
    private ChannelDataManager cdm;
    
    private PassportDataManager pdm;
    
    public MercurioRouter (EnvelopeBus bus, Commander commander, String xmlRoutingTableFilePath) throws Exception {
        super (bus, commander, xmlRoutingTableFilePath);
        
        String driver = commander.getValue ("db.driver");
        String dbmsURL = commander.getValue ("db.dbmsURL");
        String username = commander.getValue ("db.username");
        String password = commander.getValue ("db.password");
        
        cdm = new ChannelDataManager (driver, dbmsURL, username, password);
        pdm = new PassportDataManager (cdm.dm);
    }
    
    /**
     * Routing logic
     */
    public Envelope preRouteEnvelope (Envelope envelope) throws EPException {
        String msg = "";
        if(logger.isDebugEnabled ()) {
            msg = "Message received by pre router: " + envelope.toString ();
            logger.debug (msg);
        }
        if (!envelope.wellFormed ()) {
            throw new EnvelopeEPException ("Envelope not well formed");
        }
        
        if (envelope.getContent () instanceof String) {
            String c = (String) envelope.getContent ();
            if (c.length () > 129) {
                envelope.setContent (c.substring (0, 129));
            }
        }
        
        return (envelope);
    }
    
    /*
     * (non-Javadoc)
     *
     * @see guru.merlin.core.Router#getVersion()
     */
    public String getVersion () {
        return "Mercurio Router version 2.2.4";
    }
    
    /*
    private String getPassportByChannel(Envelope envelope) throws Exception {
        AbsoluteApplicationAddress app = null;
        AbsoluteApplicationAddress[] apps = null;
        String text,word,channelId = "";
        String rtn = null;
        int pos;
        try {
            channelId = envelope.getDestination().getPort();
            if ((pos = (text = envelope.getContent().toString()).indexOf(" ")) != -1) {
                word = text.substring(0, pos);
            } else {
                word = text;
            }
            apps = cdm.getApplicationBySubChannel(channelId, word);
            if (apps!=null && apps.length == 1) {
                app = apps[0];
            } else if (apps!=null && apps.length == 0) {
                apps = cdm.getApplicationByChannel(channelId);
                if (apps!=null && apps.length == 1) {
                    app = apps[0];
                }
            } else {
                throw new Exception("Atention: Was not a passport to which to assign mdr.  Passport doesn't exist.");
            }
        } catch (Exception e) {
            e.printStackTrace ();
            try {
                apps = cdm.getApplicationByChannel(channelId);
                if (apps!=null && apps.length == 1) {
                    app = apps[0];
                }
            } catch (Exception e1) {
                e1.printStackTrace ();
                throw e1;
            }
        }
        if (app != null && app.getPassport()!=null) {
            rtn = app.getPassport();
        } else {
            throw new Exception("Atention: Was not a passport to which to assign mdr.  Passport doesn't exist.");
        }
        return rtn;
    }*/
    
    private String getPassportByChannel (Envelope envelope) throws Exception {
        AbsoluteApplicationAddress app = null;
        AbsoluteApplicationAddress[] apps = null;
        String text,word,channelId = "";
        String rtn = "";
        int pos;
        try {
            channelId = envelope.getDestination ().getPort ();
            if ((pos = (text = envelope.getContent ().toString ()).indexOf (" ")) != -1) {
                word = text.substring (0, pos);
            } else {
                word = text;
            }
            apps = cdm.getApplicationBySubChannel (channelId, word);
            if (apps!=null && apps.length == 1) {
                app = apps[0];
            } else if (apps!=null && apps.length == 0) {
                apps = cdm.getApplicationByChannel (channelId);
                if (apps!=null && apps.length == 1) {
                    app = apps[0];
                }
            } else {
                throw new Exception ();
            }
        } catch (Exception e) {
            try {
                apps = cdm.getApplicationByChannel (channelId);
                if (apps!=null && apps.length == 1) {
                    app = apps[0];
                }
            } catch (Exception e1) {
                throw new Exception ();
            }
        }
        if (app != null && app.getPassport ()!=null) {
            rtn = app.getPassport ();
            logger.info ("El pasaporte es :"+rtn);
        } else {
            this.handleError (envelope, new Exception ("Atention: Was not a passport to which to assign mdr.  Passport doesn't exist."), "Handling Error");
        }
        
        return rtn;
    }
    
    
    public Object preProcesingAction (Envelope envelope) throws Exception {
        logger.info (envelope.toStringNoContent ());
        String passport = "";
        Address from = envelope.getOrigin ();
        Address to = envelope.getDestination ();
        
        logger.debug ("Procesing envelope from: " + from.getClass ().getName () + " to: " + to.getClass ().getName ());
        
        //Buscando el pasaporte que pertenece a esta transaccin
        
        if (from instanceof RelativeApplicationAddress) {
            passport = ((RelativeApplicationAddress) from).getVariable();
        } else if (to instanceof RelativeApplicationAddress) {
            try {
                passport = getPassportByChannel(envelope);                
            }catch (Exception e){
                throw e;
            }            
        } else {
            throw new Exception("Atention: Was not a passport to which to assign mdr ");
        }
        
        if (passport==null) {
            Exception e3 = new Exception ("Atention: Was not a passport to which to assign mdr.  Passport doesn't exist.");
            this.handleError (envelope, e3, "Handling Error");
            throw e3;
        }
        Long mrd_id = pdm.createMDR (passport, from.toString (), to.toString (), envelope.getContent ().toString ().length (), envelope.getComment (), Integer.parseInt (envelope.getId ()), -1);
        return new PreProcessingReference (envelope, mrd_id, passport);
    }
    
    public void preProcesingActionCompensator (Object actionReference) throws Exception {
        PreProcessingReference ppr = null;
        try {
            ppr = (PreProcessingReference) actionReference;
        } catch (Exception e) {
            throw e;
        }
        
        Envelope envelope = ppr.getEnvelope ();
        
        String passport = "";
        Address from = envelope.getOrigin ();
        Address to = envelope.getDestination ();
        //AbsoluteApplicationAddress aaa;
        
        if (from instanceof RelativeApplicationAddress) {
            passport = ((RelativeApplicationAddress) from).getVariable ();
        } else if (to instanceof RelativeApplicationAddress) {
            passport = ppr.getPassport ();
        } else {
            throw new Exception ("ATENTION: The passport of mdr was not able to eliminate ");
        }
        pdm.deleteMDR (passport, to.toString (), Integer.parseInt (envelope.getId ()), ppr.getMdr_id ());
    }
    
    /**
     * Hace persistente el procesamientos de un objeto Envelope. Actualiza el campo "commit" de la
     * base de datos MDR
     *
     * @param actionReference
     *            Objeto referencia del preprocesamiento realizado.
     * @throws CantHandException
     */
    public void commitPreProcesingAction (Object actionReference) throws EPException {
        PreProcessingReference ppr = (PreProcessingReference) actionReference;
        try {
            pdm.setCommitMDR (ppr.getMdr_id ());
        } catch (Exception e) {
            throw new InfrastructureEPException (e.toString ());
        }
    }
    
    public String getTime () {
        Calendar calendar = new GregorianCalendar ();
        SimpleDateFormat formatter = new SimpleDateFormat ("yyyy-MM-dd hh:mm:ss");
        return formatter.format (calendar.getTime ());
    }
    
    /**
     * @author sventura
     *
     * Los objetos de esta clase son pasados como referencia a los mtodo
     * preProcesingActionCompensator y handenvelope del procesin action, en el EPContainer. Ventana -
     * Preferencias - Java - Estilo de cdigo - Plantillas de cdigo
     */
    class PreProcessingReference{
        Envelope envelope;
        Long mdr_id;
        String passport;
        
        /**
         * @param envelope
         * @param mdr_id
         */
        public PreProcessingReference (Envelope envelope, Long mdr_id, String passport) {
            super ();
            this.envelope = envelope;
            this.mdr_id = mdr_id;
        }
        
        /**
         * @return Devuelve envelope.
         */
        public Envelope getEnvelope () {
            return envelope;
        }
        
        /**
         * @param envelope
         *            El envelope a establecer.
         */
        public void setEnvelope (Envelope envelope) {
            this.envelope = envelope;
        }
        
        /**
         * @return Devuelve mdr_id.
         */
        public Long getMdr_id () {
            return mdr_id;
        }
        
        /**
         * @param mdr_id
         *            El mdr_id a establecer.
         */
        public void setMdr_id (Long mdr_id) {
            this.mdr_id = mdr_id;
        }
        
        /**
         * @return Devuelve passport.
         */
        public String getPassport () {
            return passport;
        }
        
        /**
         * @param passport
         *            El passport a establecer.
         */
        public void setPassport (String passport) {
            this.passport = passport;
        }
    }
    
}